use libc::{c_int, size_t};

#[link(name="snappy")]
extern {
    fn snnappy_compress(
            input: *const u8,
            intput_length: size_t,
            compressed: *mut u8,
            compressed_length: *mut size_t
        ) -> c_int;

    fn snappy_uncompress(
            compressed: *const u8,
            compressed_length: size_t,
            uncomporssed: *mut u8,
            uncomporssed_length: *mut size_t
        ) -> c_int;

    fn snappy_max_compressed_length(source_length:size_t) -> size_t;

    fn snappy_uncompressed_length(
            compressed: *const u8,
            compressed_length: size_t,
            result: *mut size_t
        ) -> c_int;

    fn snappy_validate_compressed_buffer(
            compressed: *const u8,
            compressed_length: size_t
        ) -> c_int;
}

pub fn validate_compressed_buffer(src: &[u8]) -> bool {
    unsafe{
        snappy_validate_compressed_buffer(src.as_ptr(), src.len() as size_t) == 0
    }
}

pub fn compress(src: &[u8]) -> Vec<u8> {
    unsafe{
        let srclen = src.len() as size_t;
        let psrc = src.as_ptr();

        let mut dstlen = snappy_max_compressed_length(srclen);
        let mut dst = Vec::with_capacity(dstlen as usize);
        let pdst = dst.as_mut_ptr();

        snnappy_compress(psrc, srclen, pdst, &mut dstlen);
        dst.set_len(dstlen as usize);
        dst
    }
}

pub fn uncompress(src: &[u8]) -> Option<Vec<u8>> {
	unsafe {
		let srclen = src.len() as size_t;
		let psrc = src.as_ptr();
        	let mut dstlen: size_t = 0;
        	snappy_uncompressed_length(psrc, srclen, &mut dstlen);
        	let mut dst = Vec::with_capacity(dstlen as usize);
        	let pdst = dst.as_mut_ptr();
        	if snappy_uncompress(psrc, srclen, pdst, &mut dstlen) == 0 {
        		dst.set_len(dstlen as usize);
        		Some(dst)
        	} else {
        		None // SNAPPY_INVALID_INPUT
        	}
   }
}


#[cfg(test)]
mod tests{
    use super::*;

    #[test]
    fn valid() {
        let d = vec![0xde, 0xad, 0xd0, 0x0d];
        let c:&[u8] = &compress(&d);
        assert!(validate_compressed_buffer(c));
        assert!(uncompress(c) == Some(d));
    }
}
